package com.cskaoyan.mall.product.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cskaoyan.mall.common.constant.RedisConst;
import com.cskaoyan.mall.mq.constant.MqTopicConst;
import com.cskaoyan.mall.mq.producer.BaseProducer;
import com.cskaoyan.mall.product.cache.RedisCache;
import com.cskaoyan.mall.product.client.SearchApiClient;
import com.cskaoyan.mall.product.converter.dto.PlatformAttributeInfoConverter;
import com.cskaoyan.mall.product.converter.dto.SkuInfoConverter;
import com.cskaoyan.mall.product.converter.dto.SpuInfoConverter;
import com.cskaoyan.mall.product.dto.*;
import com.cskaoyan.mall.product.mapper.*;
import com.cskaoyan.mall.product.model.*;
import com.cskaoyan.mall.product.query.SkuImageParam;
import com.cskaoyan.mall.product.query.SkuInfoParam;
import com.cskaoyan.mall.product.query.SkuPlatformAttributeValueParam;
import com.cskaoyan.mall.product.query.SkuSaleAttributeValueParam;
import com.cskaoyan.mall.product.service.SkuService;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;


@Service
public class SkuServiceImpl implements SkuService {
    @Autowired
    SkuSaleAttrValueMapper skuSaleAttrValueMapper;
    @Autowired
    SkuPlatformAttrValueMapper skuPlatformAttrValueMapper;
    @Autowired
    SkuImageMapper skuImageMapper;
    @Autowired
    SkuInfoMapper skuInfoMapper;
    @Autowired
    SkuInfoConverter skuInfoConverter;
    @Autowired
    SpuSaleAttrInfoMapper spuSaleAttrInfoMapper;
    @Autowired
    SpuInfoConverter spuInfoConverter;
    @Autowired
    PlatformAttrInfoMapper platformAttrInfoMapper;
    @Autowired
    PlatformAttrValueMapper platformAttrValueMapper;
    @Autowired
    PlatformAttributeInfoConverter platformAttributeInfoConverter;
    @Autowired
    SpuImageMapper spuImageMapper;
    @Autowired
    RedissonClient redissonClient;
    @Autowired
    SearchApiClient searchApiClient;
    @Autowired
    BaseProducer baseProducer;
    @Override
    public void saveSkuInfo(SkuInfoParam skuInfoParam) {
        String defaultImg=null;
        for (SkuImageParam skuImageParam : skuInfoParam.getSkuImageList()) {
            if (Integer.parseInt(skuImageParam.getIsDefault())==1){
                defaultImg=skuImageParam.getImgUrl();
                break;
            }
        }
        //开始写复杂的保存业务
        //其实也没多复杂
        SkuInfo skuInfo=SkuInfo.builder()
                .spuId(skuInfoParam.getSpuId())
                .price(skuInfoParam.getPrice())
                .skuName(skuInfoParam.getSkuName())
                .skuDesc(skuInfoParam.getSkuDesc())
                .weight(skuInfoParam.getWeight())
                .tmId(skuInfoParam.getTmId())
                .thirdLevelCategoryId(skuInfoParam.getCategory3Id())
                .skuDefaultImg(defaultImg)
                .isSale(0)
                .build();

        //然后插入
        skuInfoMapper.insert(skuInfo);

        //然后判断销售属性，进行插入
        for (SkuSaleAttributeValueParam skuSaleAttributeValueParam : skuInfoParam.getSkuSaleAttrValueList()) {
         SkuSaleAttributeValue skuSaleAttributeValue= SkuSaleAttributeValue.builder()
                 .skuId(skuInfo.getId())
                 .spuId(skuInfoParam.getSpuId())
                 .spuSaleAttrValueId(skuSaleAttributeValueParam.getSaleAttrValueId())
                 .build();

         skuSaleAttrValueMapper.insert(skuSaleAttributeValue);
        }

        //拿到平台属性，然后进行插入
        for (SkuPlatformAttributeValueParam skuPlatformAttributeValueParam : skuInfoParam.getSkuAttrValueList()) {
            SkuPlatformAttributeValue skuPlatformAttributeValue=SkuPlatformAttributeValue.builder()
                    .attrId(skuPlatformAttributeValueParam.getAttrId())
                    .valueId(skuPlatformAttributeValueParam.getValueId())
                    .skuId(skuInfo.getId())
                    .build();
            skuPlatformAttrValueMapper.insert(skuPlatformAttributeValue);
        }

        //然后插入图片相关信息
        for (SkuImageParam skuImageParam : skuInfoParam.getSkuImageList()) {
            SkuImage skuImage=SkuImage.builder()
                    .skuId(skuInfo.getId())
                    .spuImgId(skuImageParam.getSpuImgId())
                    .isDefault(skuImageParam.getIsDefault())
                    .build();
            skuImageMapper.insert(skuImage);
        }

    }

    @Override
    public SkuInfoPageDTO getPage(Page<SkuInfo> pageParam) {
        //根据分页查询内容
        Page<SkuInfo> skuInfoPage = skuInfoMapper.selectPage(pageParam, null);

        //这里要添加图片列表等信息
        //但是这些信息他又不渲染！
        //算了，累了，不写了，空着吧，吧ER图画了吧

        List<SkuInfoDTO> records = skuInfoConverter.skuInfoPO2DTOs(skuInfoPage.getRecords());
        SkuInfoPageDTO skuInfoPageDTO=new SkuInfoPageDTO();
        skuInfoPageDTO.setRecords(records);
        skuInfoPageDTO.setTotal((int) skuInfoPage.getTotal());

        return skuInfoPageDTO;
    }

    @Override
    public void onSale(Long skuId) {
        //这个地方要向布隆过滤器中添加对应的商品id
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConst.SKULOCK_SUFFIX);
        bloomFilter.add(skuId);

        //要服务间调用，调用duolaimall-search服务，要进行服务间调用
//        searchApiClient.upperGoods(skuId);
        //这个地方要改成用mq进行消息通讯
        baseProducer.sendMessage(MqTopicConst.PRODUCT_ONSALE_TOPIC,skuId);

        //先查再改再保存
        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
        skuInfo.setIsSale(1);
        skuInfoMapper.updateById(skuInfo);
    }

    @Override
    public void offSale(Long skuId) {
        //服务间调用
//        searchApiClient.lowerGoods(skuId);
        //改成服务间调用
        baseProducer.sendMessage(MqTopicConst.PRODUCT_OFFSALE_TOPIC, skuId);

        //先查再改再保存
        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
        skuInfo.setIsSale(0);
        skuInfoMapper.updateById(skuInfo);

    }

    @Override
    @RedisCache(prefix = "product:getSkuInfo")
    public SkuInfoDTO getSkuInfo(Long skuId) {

        //获取skuId相关的信息
        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
        //这个地方少写内容了，要把图片列表也查询渲染出来
        Map<String,Object> map=new HashMap<>();
        map.put("sku_id", skuId);
        List<SkuImage> skuImages = skuImageMapper.selectByMap(map);
        //要把名称和路径拼接上去
        List<SpuImage> spuImages = spuImageMapper.selectList(null);
        for (SkuImage skuImage : skuImages) {
            //然后查找对应的图片列表
            for (SpuImage spuImage : spuImages) {
                if (spuImage.getId().equals(skuImage.getSpuImgId())) {
                    skuImage.setImgName(spuImage.getImgName());
                    skuImage.setImgUrl(spuImage.getImgUrl());
                }
            }
        }
        skuInfo.setSkuImageList(skuImages);

        return skuInfoConverter.skuInfoPO2DTO(skuInfo);
    }

    @Override
    public SkuInfoDTO getSkuInfoCache(Long skuId){
        //这个地方要用一下缓存
        //这里的锁应该是要设置一下唯一的id

        //先尝试在redis里面查找是否有对应的信息
        //怎么查的？
        String id="sku:info:"+skuId;
        RBucket<SkuInfoDTO> bucket = redissonClient.getBucket(id);
        if ( bucket.get()!=null)return bucket.get();

        //现在情况是redis内没有值了，然后呢？
        //创建分布式锁，查sql

        //获取锁
        String lockKey=skuId+":lock";
        RLock redisLock = redissonClient.getLock(lockKey);
        SkuInfoDTO skuInfo;
        try{
            redisLock.lock();
            skuInfo = this.getSkuInfo(skuId);
            if (skuInfo==null){
                skuInfo=new SkuInfoDTO();
            }

            //这里给个过期时间
            Random random=new Random();
            int time= random.nextInt(0,120);
            bucket.set(skuInfo,300+time, TimeUnit.SECONDS);

        }finally {
            //释放锁
            redisLock.unlock();
        }
        return skuInfo;
    }

    @Override
    public BigDecimal getSkuPrice(Long skuId) {
        SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
        return skuInfo.getPrice();
    }

    @Override
    @RedisCache(prefix = "product:getSpuSaleAttrListCheckBySku")
    public List<SpuSaleAttributeInfoDTO> getSpuSaleAttrListCheckBySku(Long skuId, Long spuId) {
        //调mapper，然后返回
        List<SpuSaleAttributeInfo> saleAttributeInfoList = spuSaleAttrInfoMapper.selectSpuSaleAttrListCheckedBySku(skuId, spuId);

        return spuInfoConverter.spuSaleAttributeInfoPOs2DTOs(saleAttributeInfoList);
    }

    @Override
    public List<PlatformAttributeInfoDTO> getPlatformAttrInfoBySku(Long skuId) {
        //根据skuId获取平台属性相关内容
        Map<String,Object> map=new HashMap<>();
        map.put("sku_id",skuId);
        List<SkuPlatformAttributeValue> platformAttributeValues = skuPlatformAttrValueMapper.selectByMap(map);
        List<PlatformAttributeInfoDTO> platformAttributeInfos=new ArrayList<>();
        for (SkuPlatformAttributeValue skuPlatformAttributeValue : platformAttributeValues) {
            PlatformAttributeInfo attributeInfo = platformAttrInfoMapper.selectById(skuPlatformAttributeValue.getAttrId());
            PlatformAttributeValue attributeValue = platformAttrValueMapper.selectById(skuPlatformAttributeValue.getValueId());

            PlatformAttributeInfoDTO attributeInfoDTO = platformAttributeInfoConverter.platformAttributeInfoPO2DTO(attributeInfo);
            PlatformAttributeValueDTO platformAttributeValueDTO = platformAttributeInfoConverter.platformAttributeValuePO2DTO(attributeValue);
            if (platformAttributeValueDTO!=null){

                attributeInfoDTO.setAttrValueList(Arrays.asList(platformAttributeValueDTO));

                platformAttributeInfos.add(attributeInfoDTO);
            }

        }

        return platformAttributeInfos;
    }

    @Override
    public List<Long> findAllOnSaleProducts() {
        //获取所有在售的商品的uuid
        List<SkuInfo> skuInfos = skuInfoMapper.selectList(null);
        List<Long> result=skuInfos.stream().map(item->item.getId()).toList();
        return result;
    }


}
